package connect2congress.client;

import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.http.client.*;
import com.google.gwt.user.client.Timer;
import com.google.gwt.widgetideas.graphics.client.Color;
import com.google.gwt.widgetideas.graphics.client.GWTCanvas;
import connect2congress.client.legacy.Point;
import connect2congress.client.properties.Person;
import connect2congress.client.properties.Verb;
import connect2congress.client.properties.Wnom;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 * Created by IntelliJ IDEA.
 * User: peter
 * Date: Mar 13, 2010
 * Time: 8:10:48 PM
 * To change this template use File | Settings | File Templates.
 */
public class Plot extends GWTCanvas implements TimelineObserver, Renderable{

    private Connect2Congress parent;
    public Point origin = null;
    public Point opposite = null;

    private ArrayList<PlotPoint> points;
    private JsArray<Wnom> wnoms;
    private JsArray<Verb> verbs;
    private JsArray<Person> people;

    public static double MAX_VERB = 0;

    int chamber;

    private ArrayList<PlotPoint> dems = new ArrayList<PlotPoint>();
    private ArrayList<PlotPoint> reps = new ArrayList<PlotPoint>();

    private WnomComparator wc = new WnomComparator();
    private VerbComparator vc = new VerbComparator();
    private PlotPoint demMed;
    private PlotPoint repMed;
    private PlotPoint totMed;

    public static final Color PlotColor = new Color(240,240,240);

    public Plot(Point origin, Point opposite, Connect2Congress parent, int chamber, JsArray<Person> people) {
        super((int)(opposite.x-origin.x),(int)(opposite.y-origin.y));

        this.parent = parent;
        this.people = people;
        this.origin = origin;
        this.opposite = opposite;

        this.setSize(width() + "px",height() + "px");
        //this.setSize("100%","100%");
        super.setBackgroundColor(Plot.PlotColor);

        init();
    }

    private void init() {
        points = new ArrayList<PlotPoint>();
        for(int i = 0; i < people.length(); i++) {
            PlotPoint p = new PlotPoint(this);
            p.setName(people.get(i));
            p.setParty(people.get(i));
            p.setVisible(true);

            points.add(p);
        }

        demMed = new PlotPoint(this);
        demMed.setSpecial(true);
        demMed.setName("Democrat Median");
        demMed.setParty("DemMed");
        demMed.setVisible(true);

        repMed = new PlotPoint(this);
        repMed.setSpecial(true);
        repMed.setName("Republican Median");
        repMed.setParty("RepMed");
        repMed.setVisible(true);

        totMed = new PlotPoint(this);
        totMed.setSpecial(true);
        totMed.setName("Total Median");
        totMed.setParty("TotMed");

        totMed.setVisible(true);

        points.add(demMed);
        points.add(repMed);
        points.add(totMed);

        parent.addToLoop(this);

    }

    public void renderingLoop() {
        clear();
        for(int i = 0; i < points.size(); i++) {
            points.get(i).draw();
        }
        //Draw lines between medians
        this.setStrokeStyle(new Color(0,0,0,0.5f));
     /*
        beginPath();

            this.moveTo(demMed.getX(),demMed.getY());
            this.lineTo(totMed.getX(),totMed.getY());
            this.moveTo(totMed.getX(),totMed.getY());
            this.lineTo(repMed.getX(),repMed.getY());

        closePath();
            */
        this.stroke();
    }

    public void loadData(long a, long b, int type) {
        if(type == Connect2Congress.WNOM_TYPE) {
            getWnoms(a,b);
        } else if(type == Connect2Congress.VERB_TYPE) {
            getVerbs(a,b);
        }
    }

    private void getWnoms(long a, long b) {
        RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, Connect2Congress.WNOM_JSON_URL + "chamber=" + Connect2Congress.SENATE + "&start=" + a + "&end=" + b);

        try {
          Request request = builder.sendRequest(null, new RequestCallback() {
            public void onError(Request request, Throwable exception) {
              System.out.println("Couldn't retrieve JSON");
            }

            public void onResponseReceived(Request request, Response response) {
              if (200 == response.getStatusCode()) {

                wnoms = asArrayOfWnoms(response.getText());
                for(int i = 0; i < wnoms.length(); i++) {
                    for(int j = 0; j < points.size(); j++) {
                        //System.out.println("wnom() " +  wnoms.get(i).getID());
                        if(wnoms.get(i).getID() == points.get(j).getId()) {
                            points.get(j).setW(wnoms.get(i));
                        }
                    }
                }
                createOrFindWnomMedians();

              } else {
                System.out.println("Couldn't retrieve JSON (" + response.getStatusCode()
                    + ")");
              }
            }
          });
        } catch (RequestException e) {
          System.out.println("Couldn't retrieve JSON");
        }
    }
    private void getVerbs(long a, long b) {
        RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, Connect2Congress.VERB_JSON_URL + "chamber=" + Connect2Congress.SENATE + "&start=" + a + "&end=" + b);
        try {
          Request request = builder.sendRequest(null, new RequestCallback() {
            public void onError(Request request, Throwable exception) {
              System.out.println("Couldn't retrieve JSON");
            }

            public void onResponseReceived(Request request, Response response) {
              if (200 == response.getStatusCode()) {

                verbs = asArrayOfVerbs(response.getText());
                MAX_VERB = 0;
                for(int i = 0; i < verbs.length(); i++) {
                    for(int j = 0; j < points.size(); j++) {
                        if(verbs.get(i).getID() == points.get(j).getId()) {
                            points.get(j).setV(verbs.get(i));
                            if(verbs.get(i).getScore() > MAX_VERB) {
                                MAX_VERB = verbs.get(i).getScore();
                            }
                        }
                    }
                }
              createOrFindVerbMedians();

              } else {
                System.out.println("Couldn't retrieve JSON (" + response.getStatusCode()
                    + ")");
              }
            }
          });
        } catch (RequestException e) {
          System.out.println("Couldn't retrieve JSON");
        }
    }

    public double width() {
        //System.out.println("width: " + this.getStyleElement().getScrollWidth());

        //return this.getOffsetWidth();
        //System.out.println("width: " + (opposite.x-origin.x));
        return opposite.x-origin.x;
    }
    public double height() {
        //System.out.println("height; " + (opposite.y-origin.y));
        return opposite.y-origin.y;
       // System.out.println("height: " + (this.getOffsetHeight()));
        //return this.getOffsetHeight();

    }
    /**
    * Convert the string of JSON into JavaScript object.
    */
    private final native JsArray<Wnom> asArrayOfWnoms(String json) /*-{
        return eval(json);
    }-*/;
    /**
    * Convert the string of JSON into JavaScript object.
    */
    private final native JsArray<Verb> asArrayOfVerbs(String json) /*-{
        return eval(json);
    }-*/;
    /**
    * Convert the string of JSON into JavaScript object.
    */
    private final native JsArray<Person> asArrayOfPeople(String json) /*-{
        return eval(json);
    }-*/;

    public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
        return addDomHandler(handler, MouseMoveEvent.getType());
    }

    public void mouseMoved(double mouseX, double mouseY) {
        for(int i = 0; i < points.size(); i++) {
            if(points.get(i).under(mouseX,mouseY)) {
                this.parent.setToolTip(points.get(i).getName()+ ":" +points.get(i).getV());
                i = points.size();
            }
        }
    }

    public void createOrFindWnomMedians() {
        Collections.sort(points,wc);
        totMed.setW(points.get(points.size()/2).getW());
        for(int i = 0; i < points.size(); i ++) {
            if(points.get(i).getParty().toLowerCase().equals("democrat") || points.get(i).getParty().toLowerCase().equals("independent")) {
                if(dems.indexOf(points.get(i)) == -1) {
                    dems.add(points.get(i));
                }
            } else if(points.get(i).getParty().toLowerCase().equals("republican")) {
                if(reps.indexOf(points.get(i)) == -1) {
                    reps.add(points.get(i));
                }
            }
        }
        Collections.sort(dems,wc);
        demMed.setW(dems.get(dems.size()/2).getW());
        Collections.sort(reps,wc);
        repMed.setW(reps.get(reps.size()/2).getW());

    }

    public void createOrFindVerbMedians() {
        Collections.sort(points,vc);
        totMed.setV(points.get(points.size()/2).getV());
        for(int i = 0; i < points.size(); i ++) {
            if(points.get(i).getParty().toLowerCase().equals("democrat") || points.get(i).getParty().toLowerCase().equals("independent")) {
                if(dems.indexOf(points.get(i)) == -1) {
                    dems.add(points.get(i));
                }
            } else if(points.get(i).getParty().toLowerCase().equals("republican")) {
                if(reps.indexOf(points.get(i)) == -1) {
                    reps.add(points.get(i));
                }
            }
        }
        Collections.sort(dems,vc);
        demMed.setV(dems.get(dems.size()/2).getV());
        Collections.sort(reps,vc);
        repMed.setV(reps.get(reps.size()/2).getV());
    }

    private class WnomComparator implements Comparator<PlotPoint> {
        public int compare(PlotPoint o1, PlotPoint o2) {
            double d = o1.getW() - o2.getW();
            if(d < 0) {
                return -1;
            } else if (d == 0) {
                return 0;
            } else return 1;
        }
    }

    private class VerbComparator implements Comparator<PlotPoint> {
        public int compare(PlotPoint o1, PlotPoint o2) {
            double d = o1.getV() - o2.getV();
            if(d < 0) {
                return -1;
            } else if (d == 0) {
                return 0;
            } else return 1;
        }
    }

}
